﻿#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS

#include <winsock2.h>
#include <iostream>
#include<fstream>

using namespace std;
#define PORT_SERVER 6656
#define DEFAULT_TYPE 1
#define LIST_LENGTH 22
#define CONFIRM_DURATION 10000
#pragma comment(lib,"ws2_32.lib")
struct purchase_list
{
	char name[11] = { 0 };
	char pass[11] = { 0 };
	char type;

};
struct sequence_number
{
	char front[5];
	char back[5];

};
char sqpid[13];


int purchase(SOCKET sock_client);	//购买序列号
int usage(SOCKET sock_client);		//使用软件
int send_confirm();					//检验序列号
void save_pid();					//保存拓展序列号
void setup();						//从pid中读取拓展序列号保存

int main()
{
	setup();
	// 崩溃重启之后先进行识别是否还在约束时间里面；
	if (send_confirm())
	{
		while (true)
		{
			Sleep(5000);
			send_confirm();
		}
	}
	else
	{
		WSADATA wsaData;
		WORD sockVersion = MAKEWORD(2, 2);
		if (0 != WSAStartup(sockVersion, &wsaData))
		{
			cout << "Failed to retrive socket version."
				<< endl;
			return 0;
		}

		SOCKET sock_client;
		sock_client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if (INVALID_SOCKET == sock_client)
		{
			cout << "Invalid socket." << endl;
			WSACleanup();
			return 0;
		}
		sockaddr_in addr_sev;
		addr_sev.sin_family = AF_INET;
		addr_sev.sin_port = htons(6666);

		addr_sev.sin_addr.s_addr = inet_addr("127.0.0.1");
		if (SOCKET_ERROR == connect(sock_client, (sockaddr*)&addr_sev, sizeof(addr_sev)))
		{
			/*
			客户程序调用connect函数来使客户Socket s与监听于name所指定的计算机的特定端口上的服务Socket进行连接。如果连接成功，connect返回0；如果失败则返回SOCKET_ERROR。
			*/
			cout << "Failed to connect." << endl;
			WSACleanup();
			return 0;
		}
		cout << "请输入需要使用的操作\n1、购买许可证\n2、使用软件\n";
		int command;
		cin >> command;
		while (command < 1 || command>2)
		{
			cout << "输入错误，请重新输入" << endl << "请输入需要使用的操作\n1、购买许可证\n2、使用软件\n";
		}
		if (command == 1)
		{
			purchase(sock_client);
		}
		else
		{
			usage(sock_client);
			WSACleanup();
			while (true)
			{
				Sleep(1000);
				send_confirm();
			}
		}
	}
	
}
int purchase(SOCKET sock_client)
{//数据准备
	purchase_list list;
	string st;
	cout << "Start up tcp client.\n购买许可证" << endl;
	cout << "用户名:" << endl;
	cin >> st;
	cout << st;
	while (st.length() > 10)
	{
		cout << "用户名长度不能大于10,请重新输入" << endl << "用户名："<<endl;
		cin >> st;
		cout << st;
	}
	strcpy(list.name, st.c_str());
	cout << "密码:" << endl;
	cin >> st;
	while (st.length() > 10)
	{
		cout << "密码长度不能大于10,请重新输入" << endl << "密码：";
		cin >> st;
		cout << st;
	}
	strcpy(list.pass, st.c_str());
	cout << "请选择类型" << endl << "1、10人型" << endl << "2、50人型" << endl;
	int command;
	cin >> command;
	while (command < 1 || command>2)
	{
		cout << "输入错误，请重新输入" << endl<< "请选择类型" << endl << "1、10人型" << endl << "2、50人型"<<endl;
	}
	list.type = command;
	
	char buf[512];
	int recv_size = 0;
	sprintf(buf, "Mode Purchase" );
	send(sock_client, buf, strlen(buf), 0);
	memset(buf, 0, sizeof(buf));
	recv_size = recv(sock_client, buf, 512, 0);
	if (*buf != '1')exit(-1);
	memset(buf, 0, sizeof(buf));
	sprintf(buf, "USER %s", list.name);
	send(sock_client, buf, strlen(buf), 0);
	memset(buf, 0, sizeof(buf));
	recv_size = recv(sock_client, buf, 512, 0);
	if (*buf != '2')exit(-1);
	memset(buf, 0, sizeof(buf));
	sprintf(buf, "PASS %s", list.pass);
	send(sock_client, buf, strlen(buf), 0);
	memset(buf, 0, sizeof(buf));
	recv_size = recv(sock_client, buf, 512, 0);
	if (*buf != '2')exit(-1);
	memset(buf, 0, sizeof(buf));
	sprintf(buf, "TYPE %c", list.type);
	send(sock_client, buf, strlen(buf), 0);
	memset(buf, 0, sizeof(buf));
	recv_size = recv(sock_client, buf, 512, 0);
	if (*buf != '2')exit(-1);

	cout << buf << endl;
	closesocket(sock_client);
	system("PAUSE");
	return 0;
}
int usage(SOCKET sock_client)
{
	void save_pid();
	int send_confirm();
	
	cout << "请输入序列号" << endl;
	string sq;
	cin >> sq;
	while (sq.length() != 10)
	{
		cout << "序列号长度为10位，请重新输入" << endl;
		cin >> sq;
	}

	char buf[512];
	memset(buf, 0, sizeof(buf));
	int recv_size = 0;
	sprintf(buf, "Mode usage");
	send(sock_client, buf, strlen(buf), 0);
	memset(buf, 0, sizeof(buf));
	recv_size = recv(sock_client, buf, 512, 0);
	//未收到确认信息，直接退出
	if (*buf != '1')exit(-1);
	//发送序列号
	memset(buf, 0, sizeof(buf));
	sprintf(buf, "SQNO %s",sq.c_str());
	send(sock_client, buf, strlen(buf), 0);
	memset(buf, 0, sizeof(buf));
	//接受序列号检查结果，确认即可使用，否则直接退出。

	recv_size = recv(sock_client, buf, 512, 0);
	if (*buf == '3')
	{
		if (*(buf + 1) == '1')
		{
			cout << "序列号错误" << endl;
		}
		else
		{
			cout << "请稍后重试"<<endl;
		}
		closesocket(sock_client);
	}
	else
	{
		strcpy(sqpid, buf+4);
		cout << "序列号正确，欢迎使用软件A"<<endl;
		cout << sqpid << endl;
		closesocket(sock_client);
	}
	closesocket(sock_client);
	//保存主机标识码状态，以便崩溃重启后直接使用；
	save_pid();
	
	
	system("PAUSE");
	
	return 0;
}
int send_confirm()
{
	void save_pid();
	if (sqpid[0]==0)
	{
		return 0;
	}
	
	WSADATA wsaData;
	WORD sockVersion = MAKEWORD(2, 2);
	if (0 != WSAStartup(sockVersion, &wsaData))
	{
		cout << "Failed to retrive socket version."
			<< endl;
		return 0;
	}

	SOCKET sock_client;
	sock_client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == sock_client)
	{
		cout << "Invalid socket." << endl;
		WSACleanup();
		return 0;
	}
	sockaddr_in addr_sev;
	addr_sev.sin_family = AF_INET;
	addr_sev.sin_port = htons(6666);

	addr_sev.sin_addr.s_addr = inet_addr("127.0.0.1");
	if (SOCKET_ERROR == connect(sock_client, (sockaddr*)&addr_sev, sizeof(addr_sev)))
	{
		/*
		客户程序调用connect函数来使客户Socket s与监听于name所指定的计算机的特定端口上的服务Socket进行连接。如果连接成功，connect返回0；如果失败则返回SOCKET_ERROR。
		*/
		cout << "Failed to connect." << endl;
		WSACleanup();
		return 0;
	}
	char buf[512];
	memset(buf, 0, sizeof(buf));
	sprintf(buf, "Mode Confirm");
	send(sock_client, buf, strlen(buf), 0);
	memset(buf, 0, sizeof(buf));
	recv(sock_client, buf, 512, 0);
	if (*buf != '1')
	{
		cout << "服务器崩溃，请稍后再试"<<endl;
		exit(-1);
	}
	memset(buf, 0, sizeof(buf));
	sprintf(buf, "Conf %s", sqpid);
	send(sock_client, buf, strlen(buf), 0);
	memset(buf, 0, strlen(buf));
	recv(sock_client, buf, 512, 0);
	if (*buf == '2')
	{
		cout << "confirm succeed" << endl;
		closesocket(sock_client);
		WSACleanup();
		return 1;
	}
	else
	{
		cout << "confirm failed" << endl;
		closesocket(sock_client);
		WSACleanup();
		return 0;
	}
	
}
void save_pid()
{
	ofstream output = ofstream("pid.txt", ios::out);
	output << sqpid;
	output.close();
}
void setup()
{
	ifstream output = ifstream("pid.txt", ios::out);
	output >> sqpid;
	output.close();
}

